package me.fung.wubi.app.view.editor

import me.fung.keen.common.TextClipboard
import me.fung.wubi.base.io.localObject
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import kotlinx.coroutines.*
import me.fung.keen.app.view.Presenter
import me.fung.keen.common.DataWrapper
import me.fung.keen.component.message.msg
import me.fung.wubi.base.define.table.CodeTable
import me.fung.wubi.base.define.table.Lexicon
import me.fung.wubi.base.define.value.Code
import me.fung.wubi.base.define.value.Word
import me.fung.wubi.base.define.value.WordFrequency
import me.fung.wubi.worker.printer.PrintConfig
import me.fung.wubi.worker.printer.SimpleTextPrinter
import me.fung.wubi.worker.printer.TablePrinter
import mu.KotlinLogging
import java.io.File
import me.fung.wubi.app.component.swing.chooseFile
import me.fung.wubi.base.define.table.CodeItem


class EditorPresenter : Presenter() {
    val model: DataWrapper<EditorModel> = DataWrapper(EditorModel(""))
    var filterState: MutableState<Filter> = mutableStateOf(Filter())

    fun updateFilter(block: Filter.() -> Filter) {
        filterState.value = filterState.value.block()
    }

    private val logger = KotlinLogging.logger { }

    fun updateTable(
        filename: String,
        lexiconFile: String?,
        wfFilename: String?
    ) = runBlocking(Dispatchers.IO) {
        val lexiconDeferred = async {
            lexiconFile?.let {
                val file = File(lexiconFile)
                if (file.exists()) Lexicon(file).loadFromFile(file) else null
            }
        }
        val tableDeferred = async {
            val file = File(filename)
            if (file.exists()) CodeTable().loadFromFile(file) else null
        }
        val wfDeferred = async {
            wfFilename?.let { wf ->
                val wfFile = File(wf)
                if (wfFile.exists()) WordFrequency(0).loadFromFile(wfFile) else null
            }
        }
        val lexicon = lexiconDeferred.await()
        val wf = wfDeferred.await()
        val min = wf?.min() ?: filterState.value.minWF
        val max = wf?.max() ?: filterState.value.maxWF
        updateFilter {
            copy(
                minWF = min,
                maxWF = max
            )
        }

        val t = tableDeferred.await()
        model.update {
            model.data.copy(
                file = filename,
                table = t ?: model.data.table,
                lexicon = lexicon,
                wordFrequency = wf,
                version = model.data.version + 1
            )
        }
    }

    fun update() {
        model.update {
            model.data.copy(version = model.data.version + 1)
        }
    }

    fun addAndUpdate(code: Code, word: Word) {
        model.data.table.add(code, word)
        update()
    }

    private var job: Job? = null
    fun save() {
        job?.cancel()
        job = CoroutineScope(Dispatchers.IO).launch {
            val printer = SimpleTextPrinter(File(model.data.file))
            printer.print(model.data.table, PrintConfig())
        }
    }


    private val defaultPrinter: (File) -> TablePrinter = { SimpleTextPrinter(it) }
    private fun dictOutput(
        targetTable: CodeTable,
        printConfig: PrintConfig = PrintConfig(),
        printerBlock: (File) -> TablePrinter = defaultPrinter,
    ) {
        try {
            val outPutFile :String = chooseFile(localObject.path()) ?: return
            val target = File(outPutFile)
            val printer = printerBlock(target)
            printer.print(targetTable, printConfig)
            TextClipboard.copy(outPutFile)
            msg.send { info("已提取码表到：$outPutFile") }
        } catch (e: Exception) {
            logger.error { "提取码表异常：" + e.message }
            msg.send { error(e) }
        }
    }

    fun out() {
        val a = model.data.table.clone { (code, item) ->
            if (itemFilterPredicate(item)) {
                CodeItem(code).apply {
                    item.forEach { word ->
                        filterWord(this.code, word) { rWord ->
                            rWord?.also {
                                add(it)
                            }
                        }
                    }
                }
            } else null
        }
        val config = PrintConfig(noCode = model.data.outNoCode)
        dictOutput(a, config)
    }
}

val EditorPresenter.itemFilterPredicate: (CodeItem) -> Boolean
    get() = { item ->
        val modelData = model.data
        val f = filterState.value
        var r = true

        // 码长
        if (r) {
            val clList = f.clList()
            val cSize = item.code.length
            r = clList.contains(cSize) || (clList.contains(9) && cSize > 4)
        }
        // 重码数
        if (r) {
            val wList = f.wList()
            val size = item.size
            r = wList.contains(size) || (wList.contains(9) && size > 3)
        }

        val lList = f.lList()
        // 针对具体词条的过滤，仅有有符合条件的词条时才返回该codeItem
        if (r) {
            val wf = model.data.wordFrequency
            r = item.map { word ->
                // 词长度
                val b0 = {
                    item.filter {
                        lList.contains(it.length) || (lList.contains(9) && it.length > 4)
                    }.isNotEmpty()
                }

                val b1 = { lList.contains(word.length) || (lList.contains(9) && word.length > 4) }
                // 词频过滤
                val b2 = {
                    if (wf == null) true else {
                        val freq = wf.frequencyOf(word)
                        freq in f.minWF..f.maxWF
                    }
                }
                // 搜索过滤
                val b3 = { item.code.value.startsWith(f.value) || word.value.contains(f.value) }
                // 简码过滤
                val b4 = {
                    if (modelData.lexicon == null || !f.onlyShort) true else {
                        // 未取到编码，认为是全码（例如：词组，生僻字）
                        item.code != (modelData.lexicon.codeOrNull(word) ?: item.code)
                    }
                }
                b0() && b1() && b2() && b3() && b4()
            }.firstOrNull { it } ?: false
        }
        r
    }

/**
 * 显示具体的word，不符合条件的不显示
 * 不过滤搜索词条对应的内容
 */
inline fun EditorPresenter.filterWord(code: Code, word: Word, block: (Word?) -> Unit) {
    val modelData = model.data
    val f = filterState.value
    val wf = model.data.wordFrequency
    // 词频条件
    val b1 = {
        if (wf == null) true else {
            val freq = wf.frequencyOf(word)
            freq in f.minWF..f.maxWF
        }
    }
    // 词条长度
    val lList = filterState.value.lList()
    val b2 = { if (lList.contains(word.length) || (lList.contains(9) && word.length > 4)) true else false }
    // 简码
    val b3 = {
        if (modelData.lexicon == null || !f.onlyShort) true else {
            // 未取到编码，认为是全码（例如：词组，生僻字）
            code != (modelData.lexicon.codeOrNull(word) ?: code)
        }
    }

    val rw: Word? = if (b1() && b2() && b3()) word else null
    block(rw)
}
